import re
from django.core.cache import cache
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
from .models import User


class LoginBase():
    def __init__(self, context):
        self.context = context

    def get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    def handle_context(self, token, user):
        self.context['token'] = token
        self.context['username'] = user.username
        request = self.context['request']
        icon = 'http://%s/media/%s' % (request.META['HTTP_HOST'], str(user.icon))
        self.context['icon'] = icon


# 这个序列化类 只做反序列化 数据库校验 不保存 不用序列化
class MulLoginSerializer(serializers.ModelSerializer):
    # 一定要重写 username 字段 校验规则是从User中来 unique
    # 如果存在的用户 再传入该用户 自己的校验规则就会校验失败
    username = serializers.CharField(max_length=18, min_length=3)  # 一定要重写 否则校验不过去

    class Meta:
        model = User
        fields = ['username', 'password']

    def validate(self, attrs):
        # 在这完成校验 校验失败抛出异常
        user = self._get_user(attrs)
        token = self._get_token(user)

        self.context['token'] = token
        self.context['username'] = user.username
        request = self.context['request']
        icon = 'http://%s/media/%s' % (request.META['HTTP_HOST'], str(user.icon))
        self.context['icon'] = icon

        return attrs

    def _get_user(self, attrs):
        username = attrs.get('username')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = User.objects.filter(mobile=username).first()
        elif re.match(r'^.+@.+$', username):
            user = User.objects.filter(email=username).first()
        else:
            user = User.objects.filter(username=username).first()

        if not user:
            raise ValidationError("用户名或密码错误")

        password = attrs.get("password")
        if not user.check_password(password):
            raise ValidationError("用户名或密码错误")

        return user

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token


class SmsLoginSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=4, min_length=4)
    mobile = serializers.CharField(max_length=11, min_length=11)

    class Meta:
        model = User
        fields = ['mobile', 'code']

    def validate(self, attrs):
        self._check_code(attrs)
        user = self._get_user(attrs)
        token = self._get_token(user)
        self.context['token'] = token
        self.context['username'] = user.username
        request = self.context['request']
        icon = 'http://%s/media/%s' % (request.META['HTTP_HOST'], str(user.icon))
        self.context['icon'] = icon
        return attrs

    def _check_code(self, attrs):
        mobile = attrs.get('mobile')
        new_code = attrs.get('code')
        if mobile:
            old_code = cache.get("sms_cache_%s" % mobile)
            if old_code != new_code:
                raise ValidationError('验证码错误')
        else:
            raise ValidationError('没带手机号')
        return attrs

    def _get_user(self, attrs):
        mobile = attrs.get('mobile')
        return User.objects.get(mobile=mobile)  # 捕获了全局异常 get出错了也能捕获

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token


class RegisterSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=4, min_length=4, write_only=True)

    class Meta:
        model = User
        fields = ['mobile', 'code', 'password']
        extra_kwargs = {
            'password': {'write_only': True},
        }

    def validate_mobile(self, value):
        if not re.match(r'^1[3-9][0-9]{9}$', value):
            raise ValidationError('手机号不合法')
        return value

    def validate(self, attrs):
        self._check_code(attrs)
        self._per_save(attrs)
        return attrs

    def _check_code(self, attrs):
        new_code = attrs.get('code')
        mobile = attrs.get('mobile')
        old_code = cache.get("sms_cache_%s" % mobile)
        if new_code != old_code:
            raise ValidationError('验证码错误')
        return attrs

    def _per_save(self, attrs):
        attrs.pop('code')
        attrs['username'] = attrs.get('mobile')
        return attrs

    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user
